package yxy.apple.http.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.ssl.SslContext;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class HttpServer implements Runnable {
	private final int port;
	private final int threads;
	private final SslContext ssl;
	private volatile boolean closed = false;
	private volatile EventLoopGroup bossGroup;
	private volatile EventLoopGroup workGroup;
	private volatile ServerBootstrap bootstrap;

	public HttpServer(int port, int threads, SslContext ssl) {
		this.port = port;
		this.threads = threads;
		this.ssl = ssl;
	}

	public void start() {
		this.run();
	}

	public void stop() {
		this.close();
	}

	private void init() {
		closed = false;
		// 配置服务端的NIO线程组
		bossGroup = new NioEventLoopGroup();
		workGroup = new NioEventLoopGroup();
		bootstrap = new ServerBootstrap();

		bootstrap.group(bossGroup, workGroup);

		bootstrap.channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {
			@Override
			public void initChannel(SocketChannel ch) throws Exception {
				if (ssl == null) {
//				ch.pipeline().addLast("http-decoder", new HttpServerCodec());
					// server端发送的是httpResponse，所以要使用HttpResponseEncoder进行编码
					ch.pipeline().addLast(new HttpResponseEncoder());
					// server端接收到的是httpRequest，所以要使用HttpRequestDecoder进行解码
					ch.pipeline().addLast(new HttpRequestDecoder());
					// 把多个消息转换为一个单一的FullHttpRequest或是FullHttpResponse,解决Post请求参数解析
					ch.pipeline().addLast(new HttpObjectAggregator(1024 * 1024));
				} else {
//					SSLEngine sslEngine = ssl.newEngine(ch.alloc());
//					sslEngine.setUseClientMode(false);
					ch.pipeline().addLast(ssl.newHandler(ch.alloc()));
//					ch.pipeline().addLast("http-decoder", new HttpServerCodec());
					ch.pipeline().addLast(new HttpResponseEncoder());
					// server端接收到的是httpRequest，所以要使用HttpRequestDecoder进行解码
					ch.pipeline().addLast(new HttpRequestDecoder());
					// 把多个消息转换为一个单一的FullHttpRequest或是FullHttpResponse,解决Post请求参数解析
					ch.pipeline().addLast(new HttpObjectAggregator(1024 * 1024));
				}
				ch.pipeline().addLast(new HttpServerHandler(threads));
			}
		})// .option(ChannelOption.SO_BACKLOG,
			// 1024).childOption(ChannelOption.SO_KEEPALIVE, true)
				.option(ChannelOption.SO_BACKLOG, 1024).childOption(ChannelOption.SO_KEEPALIVE, true);
		;
	}

	private void bind() throws Exception {
		if (isClosed()) {
			return;
		}
		// 绑定端口，开始绑定server，通过调用sync同步方法阻塞直到绑定成功
		ChannelFuture channelFuture = bootstrap.bind(port).sync();
		System.out.println("HTTP服务器启动成功，端口号：" + port);
		// 应用程序会一直等待，直到channel关闭
		channelFuture.channel().closeFuture().sync();
		System.out.println("服务器退出完毕，端口号：" + port);
	}

	private void close() {
		closed = true;
		bossGroup.shutdownGracefully();
		workGroup.shutdownGracefully();
		System.out.println("关闭http服务器: " + port);
	}

	@Override
	public void run() {
		try {
			init();
			while (true) {
				try {
					bind();
				} catch (Exception e) {
					log.error("", e);
					e.printStackTrace();
				} finally {
					close();
				}
				Thread.sleep(2000);
			}
		} catch (Exception e) {
			log.error("", e);
			e.printStackTrace();
		}
	}

	public boolean isClosed() {
		return closed;
	}

}
